package com.zycfc.zsf.boot.util.bean;

import com.zycfc.zsf.boot.util.number.*;
import java.util.concurrent.*;
import java.io.*;
import java.util.*;

public class SystemPropertiesUtils
{
    public static Boolean getBoolean(final String name) {
        final String stringResult = System.getProperty(name);
        return BooleanMoreUtils.toBooleanObject(stringResult);
    }
    
    public static Boolean getBoolean(final String name, final Boolean defaultValue) {
        final String stringResult = System.getProperty(name);
        return BooleanMoreUtils.toBooleanObject(stringResult, defaultValue);
    }
    
    public static String getString(final String name) {
        return System.getProperty(name);
    }
    
    public static String getString(final String name, final String defaultValue) {
        return System.getProperty(name, defaultValue);
    }
    
    public static Integer getInteger(final String name) {
        return Integer.getInteger(name);
    }
    
    public static Integer getInteger(final String name, final Integer defaultValue) {
        return Integer.getInteger(name, defaultValue);
    }
    
    public static Long getLong(final String name) {
        return Long.getLong(name);
    }
    
    public static Long getLong(final String name, final Long defaultValue) {
        return Long.getLong(name, defaultValue);
    }
    
    public static Double getDouble(final String name) {
        return NumberMoreUtils.toDoubleObject(System.getProperty(name));
    }
    
    public static Double getDouble(final String name, final Double defaultValue) {
        final Double propertyValue = NumberMoreUtils.toDoubleObject(System.getProperty(name));
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static String getString(final String propertyName, final String envName, final String defaultValue) {
        checkEnvName(envName);
        String propertyValue = System.getProperty(propertyName);
        if (propertyValue != null) {
            return propertyValue;
        }
        propertyValue = System.getenv(envName);
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static Integer getInteger(final String propertyName, final String envName, final Integer defaultValue) {
        checkEnvName(envName);
        Integer propertyValue = NumberMoreUtils.toIntObject(System.getProperty(propertyName));
        if (propertyValue != null) {
            return propertyValue;
        }
        propertyValue = NumberMoreUtils.toIntObject(System.getenv(envName));
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static Long getLong(final String propertyName, final String envName, final Long defaultValue) {
        checkEnvName(envName);
        Long propertyValue = NumberMoreUtils.toLongObject(System.getProperty(propertyName));
        if (propertyValue != null) {
            return propertyValue;
        }
        propertyValue = NumberMoreUtils.toLongObject(System.getenv(envName));
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static Double getDouble(final String propertyName, final String envName, final Double defaultValue) {
        checkEnvName(envName);
        Double propertyValue = NumberMoreUtils.toDoubleObject(System.getProperty(propertyName));
        if (propertyValue != null) {
            return propertyValue;
        }
        propertyValue = NumberMoreUtils.toDoubleObject(System.getenv(envName));
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static Boolean getBoolean(final String propertyName, final String envName, final Boolean defaultValue) {
        checkEnvName(envName);
        Boolean propertyValue = BooleanMoreUtils.toBooleanObject(System.getProperty(propertyName), null);
        if (propertyValue != null) {
            return propertyValue;
        }
        propertyValue = BooleanMoreUtils.toBooleanObject(System.getenv(envName), null);
        return (propertyValue != null) ? propertyValue : defaultValue;
    }
    
    public static synchronized void registerSystemPropertiesListener(final PropertiesListener listener) {
        Properties currentProperties = System.getProperties();
        if (!(currentProperties instanceof ListenableProperties)) {
            final ListenableProperties newProperties = new ListenableProperties(currentProperties);
            System.setProperties(newProperties);
            currentProperties = newProperties;
        }
        ((ListenableProperties)currentProperties).register(listener);
    }
    
    private static void checkEnvName(final String envName) {
        if (envName == null || envName.indexOf(46) != -1) {
            throw new IllegalArgumentException("envName " + envName + " has dot which is not valid");
        }
    }
    
    static class ListenableProperties extends Properties
    {
        private static final long serialVersionUID = -8282465702074684324L;
        private List<PropertiesListener> listeners;
        
        ListenableProperties(final Properties properties) {
            super(properties);
            this.listeners = new CopyOnWriteArrayList<PropertiesListener>();
        }
        
        List<PropertiesListener> getListeners() {
            return this.listeners;
        }
        
        void setListeners(final List<PropertiesListener> listeners) {
            this.listeners = listeners;
        }
        
        void register(final PropertiesListener listener) {
            this.listeners.add(listener);
        }
        
        @Override
        public synchronized Object setProperty(final String key, final String value) {
            final Object result = ((Hashtable<String, String>)this).put(key, value);
            for (final PropertiesListener listener : this.listeners) {
                if (listener.propertyName.equals(key)) {
                    listener.onChange(key, value);
                }
            }
            return result;
        }
    }
    
    abstract static class PropertiesListener implements Serializable
    {
        private static final long serialVersionUID = 1L;
        private String propertyName;
        
        PropertiesListener(final String propertyName) {
            this.propertyName = propertyName;
        }
        
        String getPropertyName() {
            return this.propertyName;
        }
        
        void setPropertyName(final String propertyName) {
            this.propertyName = propertyName;
        }
        
        abstract void onChange(final String p0, final String p1);
    }
}
